import { LVector3 } from "../../Moduls/Tools/LMath";
import RoleControler from "../LevelControler";
import GameHandler, { BufType, LayerIndex, GameState } from "../GameHandler";
import RockerView from "../ui/RockerView";
import { LWorldScreenOptions } from "../../Moduls/Tools/Converter";
import { StrickCell, StrickCellState } from "./StrickCell";


class PlayerHandStricks{
    private freeTrans:Laya.Sprite3D;    //玩家释放积木块到地面时积木块父节点
    private attacher:Laya.Sprite3D;     //玩家拾取积木块时附加地父节点
    private trackHandPos:Laya.Sprite3D; //玩家积木堆参照玩家对象手搬积木位置
    private TempStrickSp:Laya.Sprite3D;   //临时顶替积木块，防止表现效果时碰撞检测失败

    public stricks:Array<StrickCell>;
    private TempStrick:StrickCell;

    private strickPoint:number;//用于旋转延迟的积木数组指针

    constructor(attacher:Laya.Sprite3D, trackhand:Laya.Sprite3D, free:Laya.Sprite3D, tempreplace: Laya.Sprite3D){
        this.freeTrans = free;
        this.attacher = attacher;
        this.trackHandPos = trackhand;
        this.TempStrickSp = tempreplace;
        this.stricks = [];
        this.strickPoint = 0;

        this.TempStrick = this.TempStrickSp.addComponent(StrickCell);//new StrickCell(this.TempStrickSp);
        this.TempStrick.SetState(StrickCellState.MotionLess);
    }
    public get HasStrick():boolean{
        return this.stricks.length > 0;
    }
    public Push(t:Laya.Sprite3D){
        // let collider:Laya.PhysicsCollider = t.getComponent(Laya.PhysicsCollider);
        // collider.enabled = false;
        
        let cell = t.getComponent(StrickCell);//new StrickCell(t);
        let rot = this.stricks.length > 0 ? this.stricks[this.stricks.length-1].Rotation : this.trackHandPos.transform.rotation;
        cell.TackUp(this.trackHandPos.transform,GameHandler.HandStrickScale,this,()=>{
            let cellpos = LVector3.Add(this.attacher.transform.position,new Laya.Vector3(0,this.stricks.length * GameHandler.HandStrickScale.y,0));
            cell.Set(this.attacher,cellpos,rot,GameHandler.HandStrickScale);
            cell.EnableCollider(false);
            cell.DoScale();
            this.stricks.push(cell);
        });
    }
    public PutDown(pos:Laya.Vector3) {//, rot:Laya.Quaternion){
        if(this.stricks.length <= 0 )
            return;
        this.TempStrick.Set(this.freeTrans,pos,this.trackHandPos.transform.rotation,GameHandler.GroundStrickScale);
        let cell:StrickCell = this.stricks.splice(0,1)[0];
        
        cell.DoPutDown(pos,this.trackHandPos.transform.rotation,GameHandler.GroundStrickScale);
        cell.SetParent(this.freeTrans);
        cell.EnableCollider(true);
        this.stricks.forEach(element => {
            element.ReduceHigh(-GameHandler.HandStrickScale.y);
        });
    }
    public FallDown(pos:Laya.Vector3){
        if(this.stricks.length <= 0 )
            return;
        //this.TempStrick.Set(this.freeTrans,pos,this.trackHandPos.transform.rotation,GameHandler.GroundStrickScale);
        let cell:StrickCell = this.stricks.splice(0,1)[0];
        let time = (cell.target.transform.position.y - this.trackHandPos.transform.position.y) * 500 + 500;
        cell.DoFallDown(pos,this.trackHandPos.transform.rotation,GameHandler.GroundStrickScale,time);
        cell.SetParent(this.freeTrans);
        cell.EnableCollider(true);
    }
    public OnUpdate(){
        this.attacher.transform.position = this.trackHandPos.transform.position;
        this.strickPoint = this.strickPoint++ % this.stricks.length;
        for(let i=0;i<this.stricks.length;++i){
            if(i==0){
                this.stricks[i].SetRotation(this.trackHandPos.transform.rotation);
            }
            else{
                this.stricks[i].SetRotation(this.stricks[i-1].LastRotation);
            }
        }
    }
    
    public Refrush(color:Laya.Color){
        if(this.HasStrick){
            for(let i= 0;i<this.stricks.length; ++i){
                let strick = this.stricks[i];
                Laya.timer.once(i*30,this,()=>{
                    if(strick != null){
                        strick.Refrush(this.trackHandPos.transform.rotation, color);
                    }});
            }
        }
    }

    public Clear(){
        this.stricks.forEach(element => {
            element.SetParent(GameHandler.CurLevelNode);
            element.EnableCollider(true);
        });
        this.stricks = [];
    }
}

namespace MrStricks{
    export enum PlayerAnimState{
        Idle,
        TakeStricksRun,
        NoStricksRun,
        Failed,
    }
    export class PlayerAnimControler{
        public Animator:Laya.Animator;
        public state:PlayerAnimState;
        public constructor(anim:Laya.Animator,st?:PlayerAnimState){
            this.Animator = anim;
            if(st != null)
                this.state = st;
            else
                this.state = PlayerAnimState.Idle;
        }
        public Play(st:PlayerAnimState){
            this.state = st;
            switch(this.state){
                case PlayerAnimState.Idle: {
                        this.Animator.play("Idle");
                    }break;
                case PlayerAnimState.NoStricksRun:{
                            this.Animator.play("NoStricksRun");
                    }break;
                case PlayerAnimState.TakeStricksRun:{
                        this.Animator.play("TakeStricksRun");
                }break;
                case PlayerAnimState.TakeStricksRun:{
                        this.Animator.play("Failed");
                }break;
            }
        }
        public CrossFade(st:PlayerAnimState){
            this.state = st;
            switch(this.state){
                case PlayerAnimState.Idle: {
                        this.Animator.crossFade("Idle",0.2);
                    }break;
                case PlayerAnimState.NoStricksRun:{
                            this.Animator.crossFade("NoStricksRun",0.2);
                    }break;
                case PlayerAnimState.TakeStricksRun:{
                        this.Animator.crossFade("TakeStricksRun",0.2);
                }break;
                case PlayerAnimState.TakeStricksRun:{
                        this.Animator.crossFade("Failed",0.2);
                }break;
            }
        }
    }
}

export default class PlayerControler extends Laya.Script{
    public target: Laya.Sprite3D;
    public cameraTranslate: Laya.Vector3;
    private rocker: RockerView;
    private TempStrick : Laya.Sprite3D;

    public currentAction: string = "stand";

    public speed: number = 0.04;
    private lastAngle: number = 0;
    private speedY:number = 0;
    private PlayerSafeMinY = -1;


    private ray: Laya.Ray;
    private outHitInfo: Laya.HitResult;

    private stricks:PlayerHandStricks;

    private IsAngelFly:boolean;
    private FlyHight:number;
    private WalkHight:number;
    private IsPlayerDroped:boolean;
    private IsTaskFailed:boolean;

    private m_Animator:Laya.Animator;
    private m_AnimControler:MrStricks.PlayerAnimControler;

    //private m_AnimState:string;

    constructor() {
        super();
        this.ray = new Laya.Ray(LVector3.zero, new Laya.Vector3(0, -2, 0));
        this.outHitInfo = new Laya.HitResult();
        this.cameraTranslate = LVector3.zero;
        this.PlayerSafeMinY = -1;
        this.IsAngelFly = false;
        this.FlyHight = 0.8;
        this.WalkHight = 0.5;
        this.IsPlayerDroped = false;
        this.IsTaskFailed = false;
    }

    onAwake() {
        this.rocker = GameHandler.rocker;

        this.m_Animator = this.owner.getChildByName("MOXing").getComponent(Laya.Animator) as Laya.Animator;
        this.m_AnimControler = new MrStricks.PlayerAnimControler(this.m_Animator);
    }

    onStart() {
        this.target = this.owner as Laya.Sprite3D;
        this.stricks = new PlayerHandStricks(this.owner.parent.getChildByName("PlayerHandTracker") as Laya.Sprite3D, this.owner.getChildByName("HandPoint") as Laya.Sprite3D,this.owner.parent as Laya.Sprite3D,this.owner.parent.getChildByName("TempBrick") as Laya.Sprite3D);

        this.target.transform.rotationEuler = new Laya.Vector3(0,180,0);

        this.m_AnimControler.Play(MrStricks.PlayerAnimState.Idle);
    }
    onEnable(){
        this.RegistEvent();
    }
    onDisable(){
        this.UnRegistEvent();
    }

    private RegistEvent(){
        Laya.stage.on("StrickCollect",this, this.OnStrickCollect);
        Laya.stage.on("BufActive",this, this.OnChangeSpeed);
        Laya.stage.on("EnemyAttacked",this, this.OnEnemyAttacked);
        Laya.stage.on("PlayerConflict",this, this.OnBarrierConfilick);
    }
    private UnRegistEvent(){
        Laya.stage.off("StrickCollect",this, this.OnStrickCollect);
        Laya.stage.off("BufActive",this, this.OnChangeSpeed);
        Laya.stage.off("EnemyAttacked",this, this.OnEnemyAttacked);
        Laya.stage.on("PlayerConflict",this, this.OnBarrierConfilick);
    }
    private OnStrickCollect(strick:Laya.Sprite3D){
        this.HandStrick(strick);
    }
    private OnChangeSpeed(type:BufType,active:boolean,time:number){
        if(type == BufType.SpeedUp){
            if(active){
                this.speed = 0.08;
            }
            else{
                this.speed = 0.04;
            }
        }
        else if(type == BufType.Angel){
            this.IsAngelFly = active;
            if(active){
                let pos:Laya.Vector3 = this.target.transform.position.clone();
                pos.y = this.FlyHight;
                this.target.transform.position = pos;
            }
            else
            {
                let pos:Laya.Vector3 = this.target.transform.position.clone();
                pos.y = this.WalkHight;
                this.target.transform.position = pos;
            }
        }
    }
    private OnEnemyAttacked(enemy:Laya.Sprite3D){
        this.IsTaskFailed = true;
        Laya.stage.event("GameFailed");
        let putpos:Laya.Vector3 = this.target.transform.position.clone();
        putpos.y = 0.5;
        let rand:Laya.Rand = new Laya.Rand(100);
        let range:number = this.stricks.stricks.length * 0.01 + 1;
        while(this.stricks.HasStrick){
            putpos.x -= rand.getSignedFloat() * range;
            putpos.z -= rand.getSignedFloat() * range;
            this.stricks.FallDown(putpos);
        }
    }
    private OnBarrierConfilick(target:Laya.Sprite3D){
        if(target.layer != LayerIndex.Player){
            return;
        }
        Laya.stage.event("GameFailed");
        this.IsPlayerDroped = true;
    }


    onUpdate() {
        if(this.IsTaskFailed){
            return;
        }
        if ( GameHandler.rocker != null &&this.rocker.angle != -1) {

            if(this.stricks.HasStrick){
                if(this.m_AnimControler.state != MrStricks.PlayerAnimState.TakeStricksRun){
                    this.m_AnimControler.CrossFade(MrStricks.PlayerAnimState.TakeStricksRun);
                }
            }
            else{
                if(this.m_AnimControler.state != MrStricks.PlayerAnimState.NoStricksRun){
                    this.m_AnimControler.CrossFade(MrStricks.PlayerAnimState.NoStricksRun);
                }
            }
            

            if(this.target.transform.position.y >= this.PlayerSafeMinY){
                this.target.transform.rotate(new Laya.Vector3(0, (this.rocker.angle - this.lastAngle), 0), false, false);
            }

            let speedX: number = Math.sin(this.rocker.radians) * this.speed;
            let speedZ: number = Math.cos(this.rocker.radians) * this.speed;

            this.lastAngle = this.rocker.angle;
            let rayOrigin: Laya.Vector3 = LVector3.Add(this.target.transform.position, new Laya.Vector3(speedX, 2, speedZ));
            this.ray.origin = rayOrigin; 

            if( GameHandler.GameScene.physicsSimulation.rayCast(this.ray,this.outHitInfo,100,LayerIndex.Player,LayerIndex.Player) ){
                    let hittarget:Laya.Sprite3D = this.outHitInfo.collider.owner as Laya.Sprite3D;
                    if(hittarget.name == "Brick"){
                        //hittarget.active = false;
                        this.HandStrick(hittarget);
                    }
                    else if(hittarget.name == "Dest1"){
                        hittarget.name = "Dest1_Pass";
                        Laya.stage.event("Dest1Arrived");
                        console.log("Dest1 arrived");
                    }
                    else if(hittarget.name == "AwardRock"){
                        switch(hittarget.parent.name){
                                case "DoubleIsland1":
                                {
                                    hittarget.parent.name = "DoubleIsland1_Pass";
                                    GameHandler.DiamondDouble = 2;
                                    this.stricks.Refrush(Laya.Color.BLUE);
                                }break;
                                case "DoubleIsland2":
                                {
                                    hittarget.parent.name = "DoubleIsland2_Pass";
                                    GameHandler.DiamondDouble = 5;
                                    this.stricks.Refrush(new Laya.Color(1,0.06,0.73,1));
                                }break;
                                case "DoubleIsland3":
                                {
                                    hittarget.parent.name = "DoubleIsland3_Pass";
                                    GameHandler.DiamondDouble = 5;
                                    this.stricks.Refrush(new Laya.Color(1,0.06,0.73,1));
                                }break;
                                case "DoubleIsland4":
                                {
                                    hittarget.parent.name = "DoubleIsland4_Pass";
                                    GameHandler.DiamondDouble = 10;
                                    this.stricks.Refrush(Laya.Color.GREEN);
                                }break;
                        }
                    }
                    else if(hittarget.name == "EndIsland"){
                        hittarget.name = "EndIsland_Pass";
                        this.stricks.Refrush(new Laya.Color(0,0.86,1,1));
                    }
                    else if(hittarget.name == "Dest2"){
                        hittarget.name = "Dest2_Pass";
                        Laya.stage.event("Dest2Arrived");
                    }
                    else if(hittarget.layer == LayerIndex.Barrier){
                        //this.stricks.Clear();
                        Laya.stage.event("GameFailed");
                        this.IsPlayerDroped = true;
                    }
                    //console.log("------" + hittarget.name);
            }
            else{
                if(this.IsAngelFly){

                }
                else{
                    let playerForward:Laya.Vector3 = new Laya.Vector3();
                    this.target.transform.getForward(playerForward);
                    let putpos = LVector3.Add(rayOrigin, LVector3.Multiply(-0.2,playerForward));
                    putpos.y = 0.4;
                    if(this.stricks.HasStrick){
                        this.stricks.PutDown(putpos);//, this.target.transform.rotation);
                        Laya.stage.event("Strickreduce",1);
                    }
                    else{
                        if(GameHandler.State >= GameState.DestArrive){
                            Laya.stage.event("GameOver");
                            speedX = speedZ = 0;
                        }
                        else{
                            Laya.stage.event("GameFailed");
                            this.IsPlayerDroped = true;
                        }
                    }
                }
            }
            if(this.target.transform.position.y < this.PlayerSafeMinY){
                speedX = speedZ = 0;
                
            }
            this.target.transform.translate(new Laya.Vector3(speedX, this.speedY, speedZ), false);
            this.cameraTranslate = new Laya.Vector3(speedX, 0, speedZ);
        }
        else if(this.m_AnimControler.state == MrStricks.PlayerAnimState.TakeStricksRun
            || this.m_AnimControler.state == MrStricks.PlayerAnimState.NoStricksRun){
            this.m_AnimControler.CrossFade(MrStricks.PlayerAnimState.Idle);
        }
        if(this.IsPlayerDroped){
            this.speedY = -0.1;
            this.target.transform.translate(new Laya.Vector3(0, this.speedY, 0), false);
        }
        this.stricks.OnUpdate();
    }

    private HandStrick(strick:Laya.Sprite3D){
        strick.name = "Brick_Pass";
        this.stricks.Push(strick);
        Laya.stage.event("StrickAdd",1);
    }
}